package cluedo.gui;

import java.awt.Graphics;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

import net.miginfocom.swing.MigLayout;

import cluedo.ColorPawn;
import cluedo.Pawn;
import cluedo.Player;
import cluedo.Zombie;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import static cluedo.Player.log;


/** La classe che gestisce il tabellone ed il movimento delle pedine su quest'ultimo */
public class BoardPanel extends JPanel implements ComponentListener,MouseListener{


	private static final long serialVersionUID = -1919567440581317320L;


	private final int MINSCALE=650;
	          
	
	/**
	 * Numero colonne tabellone
	 */
	private final int COLUMN=26;
	
	/**
	 * Numero righe tabellone
	 */
	private final int ROW=27;
	
	/**
	 * l'immagine del tabellone
	 */
	private ImageIcon bgImg=null;
	
	/**
	 * Il nostro player
	 */
	private Player myPlayer;
	
	
	/**
	 * controlla se sono gia' mostrati i passaggi segreti
	 */
	private boolean secretShown=false;
	
	/**
	 * Mappa per gestire il caso di piu' pedine in una stanza
	 * Per ogni stanza vengono mappate le celle che ne fanno parte 
	 * con il flag che indica se sono libere (true) od occupate (false)
	 */
	private HashMap<String,HashMap<Cell,Boolean>> roomPawns;
	
	
	/**
	 * Mappa il nome di una stanza con le celle che costituiscono le entrate della stanza
	 */
	private HashMap<String,LinkedList<Cell>> roomEnt;
		
	
	/**
	 * mappa la pedina con la cella in cui e' posizionata
	 */
	private HashMap<ColorPawn,Cell> pawnPos;
	
	/**
	 * La griglia di celle
	 */
	private Cell[][] boardCells = new Cell[ROW][COLUMN];

	/**
	 * il numero di dadi ottenuto dal lancio
	 */
	private int numDice=-1;
	
	/**
	 * Il riferimento alla MainWindow in cui e' contenuto il tabellone
	 */
	private MainWindow wind=null;

	
	/**
	 * Crea il tabellone
	 * @param myPlayer il giocatore associato alla MainWindow in cui e' situato il tabellone
	 * @param wind la MainWindow
	 */
	    public BoardPanel(Player myPlayer, MainWindow wind) {
	    	
	    	this.wind=wind;
	    	this.myPlayer=myPlayer;
	    	scaleBg(-1,MINSCALE);
	    	this.setPreferredSize(new Dimension(bgImg.getIconWidth(),bgImg.getIconHeight()));
	    	this.setMinimumSize(new Dimension(bgImg.getIconWidth(),bgImg.getIconHeight()));
	    	setLayout(new MigLayout("ins 0, wrap " + COLUMN + ", gap 0", "grow", "grow"));
	    	setBackground(Color.BLACK);
	    	this.addComponentListener(this); 
	    	initializeCells();

	    }
	   
	    
	    /**
	     * Restituisce il numero di colonne del tabellone
	     * @return vedi descrizione
	     */
	    public int getCols(){
	    	
	    	return COLUMN;
	    }
	    
	    /**
	     * Restituisce il numero di righe del tabellone
	     * @return vedi descrizione
	     */
	    public int getRows(){
	    	
	    	return ROW;
	    }
	    
	    /**
	     * crea le caselle iniziali
	     */
	    private void initializeCells(){
	    	
	    	log.println("BoardPanel: inizio creazione tabellone");
	    	
	    	pawnPos= new HashMap<ColorPawn,Cell>();	
	    	
	    	
	    	roomPawns= new HashMap<String,HashMap<Cell,Boolean>>();
	    	
	    	roomEnt= new HashMap<String,LinkedList<Cell>>();
	    	
	    	
	    	HashMap<Cell,Boolean> studyCells= new HashMap<Cell,Boolean>();
	    	HashMap<Cell,Boolean> hallCells= new HashMap<Cell,Boolean>();
	    	HashMap<Cell,Boolean> loungeCells= new HashMap<Cell,Boolean>();
	    	HashMap<Cell,Boolean> kitchenCells= new HashMap<Cell,Boolean>();
	    	HashMap<Cell,Boolean> conservatoryCells= new HashMap<Cell,Boolean>();
	    	HashMap<Cell,Boolean> diningroomCells= new HashMap<Cell,Boolean>();
	    	HashMap<Cell,Boolean> ballroomCells= new HashMap<Cell,Boolean>();
	    	HashMap<Cell,Boolean> billiardroomCells= new HashMap<Cell,Boolean>();
	    	HashMap<Cell,Boolean> libraryCells= new HashMap<Cell,Boolean>();

	    	LinkedList<Cell> studyEnt= new LinkedList<Cell>();
	    	LinkedList<Cell> hallEnt= new LinkedList<Cell>();
	    	LinkedList<Cell> loungeEnt= new LinkedList<Cell>();
	    	LinkedList<Cell> kitchenEnt= new LinkedList<Cell>();
	    	LinkedList<Cell> conservatoryEnt= new LinkedList<Cell>();
	    	LinkedList<Cell> diningroomEnt= new LinkedList<Cell>();
	    	LinkedList<Cell> ballroomEnt= new LinkedList<Cell>();
	    	LinkedList<Cell> billiardroomEnt= new LinkedList<Cell>();
	    	LinkedList<Cell> libraryEnt= new LinkedList<Cell>();
	
	    	
	    	for(int x = 0; x < ROW; x++)       

	    		for(int y = 0; y < COLUMN; y++){
	            	
	
	            	 /*pedine nella posizione iniziali
            		 * Le celle che rappresentano le posizioni iniziali delle pedine finche' non viene aggiunta la rispettiva
            		 * pedina fanno parte delle celle libere
            		 */
	    			
	            	if((x==1 && y==10) || (x==1 && y==15) || (x==18 && y==1) ||
	            			(x==(ROW-2) && y==8) || (x==7 && y==(COLUMN-2)) || (x==20 && y==24)){
	            		
	            		add(boardCells[x][y]= new Cell(true,this,x,y),"grow");
	            	}
	            	
	            	//celle esterne libere
	            	else if((x==8 && y==1) ||( x==(ROW-2) && y==17)){
	            		add(boardCells[x][y]= new Cell(true,this,x,y),"grow");
	            	}
	            	
	            	
	            	//celle stanza "Study"
	            	else if((x>=22 && x<25) && (y>=18 && y<24)){
	            		add(boardCells[x][y]= new Cell("Study",false,this,x,y),"grow");
	            		
	            		if(x>=23 && x<25 && y>=20 && y<=22)
	            			studyCells.put(boardCells[x][y], true);
	            		
	            	}	            	
	            	
	            	else if((x>=2 && x<8) && (y>=2 && y<7)){
	            		   
	        	        // celle stanza "Kitchen"
	            		
	            		add(boardCells[x][y]= new Cell("Kitchen",false,this,x,y),"grow");
	            		
	            		if((x==3 || x==5) && (y>=3 && y<=5))
	            			kitchenCells.put(boardCells[x][y], true);
	            		
	            		
	            	} 
	            	
	            	else if((((x>=11 && x<17) && (y>=2 && y<9))) || (y>=2 && y<6 && x==10)){
	            		
	            		
	            		//celle stanza "Dining Room"
	
	            		add(boardCells[x][y]= new Cell("Dining Room",false,this,x,y),"grow");
	            		
	            		if((x==13 || x==15) &&(y>=3 && y<=5))
	            			diningroomCells.put(boardCells[x][y], true);
	            		
	            		
	            	}
	            	
	            	else if((x>=20 && x<25) && (y>=2 && y<8)){
	            		
	            		//celle stanza "Lounge"
	        	            	
	            		add(boardCells[x][y]= new Cell("Lounge",false,this,x,y),"grow");
	            		
	            		if((x==21 || x==23) &&(y>=3 && y<=5))
	            			loungeCells.put(boardCells[x][y], true);
	            		
	            	} 
	            	
	            	else if (((x>=3 && x<9) && (y>=9 && y<17)) || (y>=11 && y<15 && x==2)){
	            		
	            		//celle stanza "BallRoom"
	        	            	
	            		add(boardCells[x][y]= new Cell("BallRoom",false,this,x,y),"grow");
	            		if((x==4 || x==6) &&(y==10 || y==12 || y==14))
	            			ballroomCells.put(boardCells[x][y], true);
	            		
	            		
	            	}
	            	
	            	else if((x>=19 && x<25) && (y>=10 && y<16)){
	            		
	            		//celle stanza "Hall"
	        	    		        	            	
	            		add(boardCells[x][y]= new Cell("Hall",false,this,x,y),"grow");
	            		if((x==21 || x==23) &&(y>=11 && y<=13))
	            			hallCells.put(boardCells[x][y], true);
	            		
	            	}
	            	
	            	else if((((x>=2 && x<7) && (y>=20 && y<(COLUMN-2)))) || (x>=2 && x<6 && y==19)){
	            		
	            		//celle stanza "Conservatory"
	        	     
	            		add(boardCells[x][y]= new Cell("Conservatory",false,this,x,y),"grow");
	            		if((x==3 || x==5) && (y>=21 && y<=23))
	            			conservatoryCells.put(boardCells[x][y], true);
	            		
	            	}
	            	
	            	else if((x>=9 && x<14) && (y>=19 && y<24)){
	            		
	            		//celle stanza "Billiard Room"  
	        	            	
	            		add(boardCells[x][y]= new Cell("Billiard Room",false,this,x,y),"grow");
	            		if((x==10 || x==12) && (y>=21 && y<=23))
	            			billiardroomCells.put(boardCells[x][y], true);
	            		
	            	}
	            	
	            	else if((((x>=15 && x<20) && (y>=19 && y<(COLUMN-2)))) || (x>=16 && x<19 && y==18)){
	            		
	            		//celle stanza "Library"    
	        	            	
	            		add(boardCells[x][y]= new Cell("Library",false,this,x,y),"grow");
	            		if((x==16 || x==18) && (y>=20 && y<=22))
	            			libraryCells.put(boardCells[x][y], true);
	            		
	            	}
	            	
	            	//entrate delle stanze
	            	
	            	
	            	else if(x==6 && y==17){ //entrata ballroom destra
	            	
	            		add(boardCells[x][y]= new Cell("BallRoom",true,this,x,y),"grow");
	            		ballroomEnt.add(boardCells[x][y]);
	            	}
	            	else if(x==6 && y==19){ //entrata conservatory
	            		
	            		add(boardCells[x][y]= new Cell("Conservatory",true,this,x,y),"grow");
	            		conservatoryEnt.add(boardCells[x][y]);
	            	}
	            	
	            	else if(x==8 && y==5){ //entrata kitchen
	            		add(boardCells[x][y]= new Cell("Kitchen",true,this,x,y),"grow");
	            		kitchenEnt.add(boardCells[x][y]);
	            	}
	            	
	            	else if(x==9 && y==10){ //entrata ballroom davanti
	            		add(boardCells[x][y]= new Cell("BallRoom",true,this,x,y),"grow");
	            		ballroomEnt.add(boardCells[x][y]);
	            	}
	            	
	            	else if(x==10 && y==18){ //entrata billiard room
	            		add(boardCells[x][y]= new Cell("Billiard Room",true,this,x,y),"grow");
	            		billiardroomEnt.add(boardCells[x][y]);
	            	}
	            	
	            	else if(x==17 && y==7){ //entrata dining room
	            		add(boardCells[x][y]= new Cell("Dining Room",true,this,x,y),"grow");
	            		diningroomEnt.add(boardCells[x][y]);
	            	}
	            	
	            	else if(x==17 && y==17){ //entrata library
	            		add(boardCells[x][y]= new Cell("Library",true,this,x,y),"grow");
	            		libraryEnt.add(boardCells[x][y]);
	            	}
	            	
	            	else if(x==18 && y==13){ //entrata hall
	            		add(boardCells[x][y]= new Cell("Hall",true,this,x,y),"grow");
	            		hallEnt.add(boardCells[x][y]);
	            	}
	            	
	            	else if(x==19 && y==7){ //entrata lounge
	            		add(boardCells[x][y]= new Cell("Lounge",true,this,x,y),"grow");
	            		loungeEnt.add(boardCells[x][y]);
	            	}

	            	else if(x==21 && y==18){ //entrata study
	            		add(boardCells[x][y]= new Cell("Study",true,this,x,y),"grow");
	            		studyEnt.add(boardCells[x][y]);
	            	}
	            	
	            	
	            	else if((x>=11 && x<18) && (y>=11 && y<16)){
	            		
	            		//celle non utilizzabili al centro    
	            		add(boardCells[x][y]= new Cell(false,this,x,y),"grow");
	            	}
	            	
	            	else if((x==2 && y==7) || (x==2 && y==18)){
	            		
	            		//celle non utilizzabili nella parte alta al fianco di kitchen e conservatory
	        	    	
	            		add(boardCells[x][y]= new Cell(false,this,x,y),"grow");	            		
	            		
	            	}
	               	
	            	
	            	else if(((x==0 ||x==1) && y<COLUMN) || ((y==0 || y==1) && x<ROW) || ( ((x==(ROW-1)) || (x==(ROW-2))) 
	            	
	            	&& y<COLUMN) ||(x<ROW && (y==(COLUMN-1) || y==(COLUMN-2)))){ 
	            		
	            		//celle non utilizzabili esterne ( nel check devono rimanere prima dell'else finale)
	 
	            		
	            		add(boardCells[x][y]= new Cell(false,this,x,y),"grow");	

	            	}
	            	
	            	
	            	else{  
	            	
	            		//celle libere
	            		
	            		add(boardCells[x][y]= new Cell(true,this,x,y),"grow");
	            	
	            	}
	            	
	            }
	    	
        	roomPawns.put("Study",studyCells);
        	roomPawns.put("Library",libraryCells);
        	roomPawns.put("Billiard Room",billiardroomCells);
        	roomPawns.put("Conservatory",conservatoryCells);
        	roomPawns.put("Hall",hallCells);
        	roomPawns.put("BallRoom",ballroomCells);
        	roomPawns.put("Lounge",loungeCells);
        	roomPawns.put("Dining Room",diningroomCells);
        	roomPawns.put("Kitchen",kitchenCells);
  
        	roomEnt.put("Study",studyEnt);
        	roomEnt.put("Library",libraryEnt);
        	roomEnt.put("Billiard Room",billiardroomEnt);
        	roomEnt.put("Conservatory",conservatoryEnt);
        	roomEnt.put("Hall",hallEnt);
        	roomEnt.put("BallRoom",ballroomEnt);
        	roomEnt.put("Lounge",loungeEnt);
        	roomEnt.put("Dining Room",diningroomEnt);
        	roomEnt.put("Kitchen",kitchenEnt);
	 
        	log.println("BoardPanel: il Tabellone e' stato creato");
        	
	    }
	   
	    
	    /**
	     * Restituisce l'altezza dell'immagine di backgroung
	     * @return vedi descrizione
	     */
	    public int getBgHeight(){
	    	
	    	return bgImg.getIconHeight();
	    }
	    
	    
	    /**
	     * Restituisce la larghezza dell'immagine di backgroung
	     * @return vedi descrizione
	     */
	    public int getBgWidth(){
	    	return bgImg.getIconWidth();
	    }
	    
	    /**
	     * Scala il background
	     * @param width la nuova larghezza
	     * @param height la nuova altezza
	     */
	    private void scaleBg(int width,int height){
	    	
	    	Image tmpImg= new ImageIcon(BoardPanel.class.getResource("/img/cluedoboard.jpg")).getImage();
		    this.bgImg = new ImageIcon(
	        		tmpImg.getScaledInstance(width, height, Image.SCALE_SMOOTH)
	        		);
	    	this.repaint();
	    }
	    
	    
	    /**  Disegna il tabellone come sfondo del BoardPanel*/ 
	    @Override
	    protected void paintComponent(Graphics g)
		{
	    	
	    	super.paintComponent(g);
	    	
	    	g.drawImage(bgImg.getImage(), 0, 0,null); 
	    	
	    	
		}


	    /**
	     * Gestisce il ridimensionamento del pannello (BoardPanel)
	     */
		@Override
		public void componentResized(ComponentEvent e) {
			scaleBg(e.getComponent().getWidth(),e.getComponent().getHeight());
		}

		
		
		/**
		 * Controlla su quali caselle puo' spostarsi la pedina compatibilmente con il numero ottenuto tirando il dado
		 * @param nummDice il numero ottenuto tirando il dado
		 */
		
		
		public void findMoveCells(int numDice){
			
			log.println("BoardPanel: devo controllare su quali celle mi posso muovere per evidenziarle correttamente. " +
					"Il parametro passato a findMoveCells() e' numDice="+numDice);
			
			this.numDice=numDice;
			
			ColorPawn key= myPlayer.getPawn().getColor();
			
			//recupero la posizione in cui e' la mia pedina
			Cell cell=pawnPos.get(key);
			
			int xCoord =cell.getXCoord();
			int yCoord =cell.getYCoord();
			
			int highlightedCells=0;
			
			//evidenzia celle in cui mi posso muovere
			
			if(!cell.isInRoom()){ //la pedina e' fuori dalla stanza
				
				log.println("BoardPanel: prima di iniziare la ricerca delle celle su cui posso muovermi considero che la mia pedina e' fuori da una stanza");
				
				highlightedCells=searchCells(xCoord,yCoord,0,cell.isEntrance(),numDice,null);
			
			}
			else{ // la pedina e' dentro ad una stanza
				
				log.println("BoardPanel: prima di iniziare la ricerca delle celle su cui posso muovermi considero che la mia pedina e' dentro ad una stanza");
				
				String roomName = cell.getRoomName();
				
				if(!secretShown)
					showSecretPassage();
				
								
				LinkedList<Cell> entList = roomEnt.get(roomName);
					
				int xRoomEntrance;
				int yRoomEntrance;
				
				for(Cell entrance: entList){
					
					xRoomEntrance =entrance.getXCoord();
					yRoomEntrance =entrance.getYCoord();
				
					highlightedCells+=searchCells(xRoomEntrance,yRoomEntrance,0,true,numDice-1,roomName); //numDice-1 perche' parto da dentro la stanza
				
				}
				
			}
						
			log.println("BoardPanel: sono state trovate "+highlightedCells+" celle in cui mi posso muovere");
			System.out.println("BoardPanel: sono state trovate "+highlightedCells+" celle in cui ti puoi muovere");
			
		}
		
		
		/**
		 * Controlla se la pedina puo' usare un passagio segreto ed evidenzia
		 * le celle della stanza che puo' raggiungere attraverso quel passaggio segreto
		 * @param roomName
		 */
		public void showSecretPassage(){
			
			log.println("BoardPanel: controllo se la mia pedina puo' usare un passaggio segreto");
			
			if(!myPlayer.getPawn().isInRoom()){
				log.println("BoardPanel: la mia pedina NON puo' usare un passaggio segreto perche' non e' in una stanza");
				return;
			}
			
			if(secretShown){
				log.println("BoardPanel: la mia pedina puo' usare un passaggio segreto e sono gia' evidenziate le celle per poterlo usare");
				return;
			}
			
			ColorPawn pawnCol=myPlayer.getPawnColor();
			Cell myCell=pawnPos.get(pawnCol);
			
			String roomName=myCell.getRoomName();
			
			if(roomName==null) return;
			
			log.println("BoardPanel: evidenzio la mia cella");
			
			myCell.highlightCell(); //evidenzio la cella in cui mi trovo nella stanza che se per errore premo il dado
			// invece di formulare soluzione/ipotesi posso rimediare cliccando sulla mia stessa cella
			
			String secretRoom=null;
			
			
			if(roomName.equals("Lounge")){
				
				secretRoom="Conservatory";
			}
			else if(roomName.equals("Kitchen")){
				
				secretRoom="Study";
				
			}
			else if(roomName.equals("Study")){
				
				secretRoom="Kitchen";
				
			}
			else if(roomName.equals("Conservatory")){
				
				secretRoom="Lounge";
	
			}
			else{
				log.println("BoardPanel: la stanza "+roomName+" in cui mi trovo non dispone di passaggi segreti. Non faccio niente");
				return;
			}
			
			log.println("BoardPanel: la mia pedina (che si trova nella stanza "+roomName+") puo' usare un passaggio segreto per passare nella stanza "+secretRoom);
			
			//evidenzio le celle libere della stanza che posso raggiungere dal passaggio segreto
			HashMap<Cell,Boolean> roomCells = roomPawns.get(secretRoom);
			
			for (Map.Entry<Cell,Boolean> entry : roomCells.entrySet()){
				
				Cell cell=entry.getKey();
				if(entry.getValue() && (!cell.isHighlighted()))
					cell.highlightCell();
				
			}
			
			secretShown=true;
				
		}
		
		/**
		 * Rimuove l'evidenziazione delle celle della stanza a cui posso accedere tramite il passaggio segreto
		 */
		public void hideSecretPassage(){
			
			log.println("BoardPanel: Controllo se devo nascondere l'evidenziazione dalle celle della stanza a cui posso accedere tramite passsaggio segreto");
			
			if(!secretShown){
				log.println("BoardPanel: le celle della stanza accessibile tramite passaggio segreto non sono evidenziate, non faccio niente");
				return;
			}
			
			ColorPawn pawnCol=myPlayer.getPawnColor();
			Cell myCell=pawnPos.get(pawnCol);
			
			String roomName=myCell.getRoomName();
			
			if(roomName==null) return;
			
			
			secretShown=false;
			
			
			if(myCell.isHighlighted()){
				
				log.println("BoardPanel: rimuovo evidenziazione dalla mia cella");
				myCell.removeHighlight(); 
				
			}
			
			String secretRoom=null;
			
			
			if(roomName.equals("Lounge")){
				
				secretRoom="Conservatory";
			}
			else if(roomName.equals("Kitchen")){
				
				secretRoom="Study";
				
			}
			else if(roomName.equals("Study")){
				
				secretRoom="Kitchen";
				
			}
			else if(roomName.equals("Conservatory")){
				
				secretRoom="Lounge";
	
			}
			else {
				log.println("BoardPanel: dalla stanza "+roomName+" NON posso usare alcun passaggio segreto quindi non faccio niente");
				return;
			}
			
			log.println("BoardPanel rimuovo l'evidenziazione dalle celle della stanza "+roomName);
			
			//rimuovo l'evidenziazione dalle celle della stanza segreta
			HashMap<Cell,Boolean> roomCells = roomPawns.get(secretRoom);
			
			for (Map.Entry<Cell,Boolean> entry : roomCells.entrySet()){
				
				Cell cell=entry.getKey();
				if(entry.getValue() && (cell.isHighlighted()))
					cell.removeHighlight();
				
			}
			
			
		}
		
		
		
		
		/**
		 * Evidenzia le celle su cui la pedina si puo' spostare
		 * @param x la coordinata x della cella attuale
		 * @param y la coordinata y della cella attuale
		 * @param offset di quante celle si e' gia' spostata la pedina
		 * @param isEntrance la cella precedente a questa e' un'entrata
		 * @param numDice il numero ottenuto dal lancio del dado
		 * @param startRoom il nome della stanza da cui parte la pedina o null se la pedina parte esternamente ad una stanza
		 * @return il numero di celle in cui si puo' spostare la pedina partendo dalla cella di coordinate x e y passate
		 */
		private int searchCells(int x,int y, int offset,boolean isEntrance, int numDice, String startRoom ){
			
			
			//System.out.println("Coord: "+x+" "+y);
			//System.out.println("Dice: "+numDice);
			//System.out.println("RoomNameInit: "+startRoom);
			//System.out.println("offset: "+offset);
			//System.out.println("isEntrance: "+isEntrance);
											
			if(offset>numDice || x>(ROW-1) || x<0 || y<0 || y>(COLUMN-1)){ //ho raggiunto il massimo spostamento possibile
			
				//System.out.println("Return 0 ---> Uscito da tabellone o massimo spostamento raggiunto");
				return 0; 
			
			}
			
			Cell currentCell=boardCells[x][y];
			
						
			if(isEntrance && (startRoom!=null) && currentCell.isInRoom() && currentCell.getRoomName().equals(startRoom)){ //se sono gia' in una stanza non posso entrare in un'altra cella della stessa stanza
				
				//System.out.println("Return 0 ---> Sono partito da dentro una stanza, voglio usare altra cella stessa stanza");
				
				return 0;
				
			}
				
			if(!currentCell.isUsable()){ //non posso muovermi su questa cella
				//System.out.println("Return 0 ---> Questa cella non e' utilizzabile");
				return 0; 
			}
			
			if(!currentCell.isEmpty() && (currentCell.getPawn().getColor()!=myPlayer.getPawnColor())){ //controllo se la cella e' occupata da un'altra pedina
				//System.out.println("Return 0 ---> cella occupata non da me");
				return 0;
			}
			
			if(currentCell.isInRoom() && (!isEntrance)){ //non evidenzio la cella di una stanza se non posso raggiungerla tramite l'entrata della stanza
				//System.out.println("Return 0 ---> cella della stanza ["+ currentCell.getRoomName()+"] senza usare entrata");
				return 0; 
			}
												
			int numRes=0;
			
			if(!currentCell.isHighlighted() && !currentCell.isInRoom()){
				currentCell.highlightCell();
				numRes++;
				//System.out.println("Evidenzio cella (" + currentCell.getXCoord() + ", " + currentCell.getYCoord() +")" );
			}
			
			if(currentCell.isInRoom() && (isEntrance)){ //posso entrare in una stanza
				
				String roomName = currentCell.getRoomName();
				
				//System.out.println("Evidenzio celle della stanza "+roomName);
				
				//evidenzio le celle libere nella stanza

				HashMap<Cell,Boolean> roomCells = roomPawns.get(roomName);
				
				for (Map.Entry<Cell,Boolean> entry : roomCells.entrySet()){
					//System.out.println(roomName);
					
					Cell cell=entry.getKey();
					if(entry.getValue() && (!cell.isHighlighted())){
						cell.highlightCell();
						numRes++;
						//System.out.println("Evidenzio cella-stanza (" + cell.getXCoord() + ", " + cell.getYCoord() +")" );
					}
					
				}
				
				return numRes;
					
			}
			
			
			
			
			//System.out.println("");
				
			
			
			boolean ent = currentCell.isEntrance();
			
			int right=searchCells(x,y+1,offset+1,ent,numDice,startRoom); //cella a destra
			int left=searchCells(x,y-1,offset+1,ent,numDice,startRoom); //cella a sinistra
			int up=searchCells(x-1,y,offset+1,ent,numDice,startRoom); //cella sopra
			int down=searchCells(x+1,y,offset+1,ent,numDice,startRoom); //cella sotto
			
			
			return (numRes+right+left+up+down);			
			
		}
		
		/**
		 * Mostra graficamente la pedina di un altro giocatore muoversi sul tabellone
		 * @param player il giocatore che ha mosso la pedina
		 * @param x la coordinata x di arrivo della pedina
		 * @param y la coordinata y di arrivo della pedina
		 */
		public void movePawn(Zombie player, int x, int y){
			
			log.println("BoardPanel: muovo la pedina di "+player.getNickname()+" sul tabellone");
			
			if(x<0 || y<0 || x>(ROW-1) || y>(COLUMN-1)){
				System.err.println("BoardPanel: le coordinate in cui spostare la pedina sono errate");
				return;
			}
			
			ColorPawn key= player.getPawnColor();

			
			Cell oldCell=pawnPos.get(key);
			
			oldCell.removePawn();

			
		    //Se la pedina era in una stanza ed e' uscita devo segnare la cella della stanza come libera

			if(oldCell.isInRoom() && 
					((!boardCells[x][y].isInRoom()) || 
							(boardCells[x][y].isInRoom() && (!oldCell.getRoomName().equals(boardCells[x][y].getRoomName()))))){
				
				
				log.println("BoardPanel: la pedina di "+player.getNickname()+" era nella stanza "+oldCell.getRoomName()+"ed e' uscita. " +
						"Segno la cella della stanza come libera");
				
				HashMap<Cell,Boolean> roomCells = roomPawns.get(oldCell.getRoomName());
				
				roomCells.put(oldCell,true);
				
				
				
			}
			
				
			boardCells[x][y].insertPawn(new Pawn(key));
			
			//se la pedina e' andata sulla cella di una stanza devo segnare la cella come occupata
			
			if(boardCells[x][y].isInRoom()){
			
				String roomName = boardCells[x][y].getRoomName();
					
				HashMap<Cell,Boolean> roomCells = roomPawns.get(roomName);
			
				for (Map.Entry<Cell,Boolean> entry : roomCells.entrySet()){
				
					Cell cell=entry.getKey();
				
					if(cell.equals(boardCells[x][y])){
						log.println("BoardPanel: la pedina di "+player.getNickname()+" e' andata su una cella della stanza "+roomName+"." +
								"Segno la cella come occupata");
						entry.setValue(false); //cella occupata
						System.out.println("BoardPanel: "+player.getNickname()+" ha occupato una cella della stanza " + roomName);

					}
				
				}
			
			
			}
			
			
			pawnPos.put(key,boardCells[x][y]);
			log.println("BoardPanel: ho aggiornato la posizione della pedina di "+player.getNickname());
			
			
			System.out.println("BoardPanel: la posizione della pedina di "+player.getNickname()+" e' stata aggiornata");
			
			
		}
		
		
		/**
		 * Aggiunge una pedina associata ad un player nella sua posizione iniziale
		 * Questo metodo e' usato ad inizio partita per posizionare le pedine
	     * @param player il giocatore di cui deve essere aggiunta la pedina
	     */
		public void addPawn(Zombie player){
			
			ColorPawn key=null;
			key = player.getPawnColor();
			
			String playerName = player.getNickname();

			log.println("Aggiungo la pedina di "+playerName+" al tabellone");
			
			if(key==ColorPawn.WHITE){
			      
        		Pawn white = new Pawn(ColorPawn.WHITE);
        		boardCells[1][10].insertPawn(white);
        		pawnPos.put(key,boardCells[1][10]);
        		log.println("BoardPanel: Aggiunta la pedina di Mrs White ("+playerName+")");
        		System.out.println("BoardPanel: Aggiunta la pedina di Mrs White ("+playerName+")");
        		
        	}
        	else if(key==ColorPawn.GREEN){
        		Pawn green = new Pawn(ColorPawn.GREEN);
        		boardCells[1][15].insertPawn(green);
        		pawnPos.put(key,boardCells[1][15]);
        		log.println("BoardPanel: Aggiunta la pedina di Rev. Green ("+playerName+")");
        		System.out.println("BoardPanel: Aggiunta la pedina di Rev. Green ("+playerName+")");
        	}
	    	
        	else if(key==ColorPawn.YELLOW){
        		Pawn yellow = new Pawn(ColorPawn.YELLOW);
        		boardCells[18][1].insertPawn(yellow);
        		pawnPos.put(key,boardCells[18][1]);
        		log.println("BoardPanel: Aggiunta la pedina di Colonel Mustard ("+playerName+")");
        		System.out.println("BoardPanel: Aggiunta la pedina di Colonel Mustard ("+playerName+")");
        	}
        	
        	else if(key==ColorPawn.RED){
        		Pawn red = new Pawn(ColorPawn.RED);
        		boardCells[ROW-2][8].insertPawn(red);
        		pawnPos.put(key,boardCells[ROW-2][8]);
        		log.println("BoardPanel: Aggiunta la pedina di Miss Scarlett ("+playerName+")");
        		System.out.println("BoardPanel: Aggiunta la pedina di Miss Scarlett ("+playerName+")");
        	}
        	
        	else if(key==ColorPawn.BLUE){
        		Pawn blue = new Pawn(ColorPawn.BLUE);
        		boardCells[7][COLUMN-2].insertPawn(blue);
        		pawnPos.put(key,boardCells[7][COLUMN-2]);
        		log.println("BoardPanel: Aggiunta la pedina di Mrs Peacock ("+playerName+")");
        		System.out.println("BoardPanel: Aggiunta la pedina di Mrs Peacock ("+playerName+")");
        	}
        	
        	else if(key==ColorPawn.MAGENTA){
        		Pawn magenta = new Pawn(ColorPawn.MAGENTA);
        		boardCells[20][24].insertPawn(magenta);
        		pawnPos.put(key,boardCells[20][24]);
        		log.println("BoardPanel: Aggiunta la pedina di Professor Plum ("+playerName+")");
        		System.out.println("BoardPanel: Aggiunta la pedina di Professor Plum ("+playerName+")");
        	}
			
        	else
        		
        		System.err.println("BoardPanel: il colore della pedina da aggiungere non e' esatto");
										
		}
		
		
		/**
		 * Disabilita le celle evidenziate
		 */
		public void disableHighlightCells(){
			
			if(numDice!=-1){ //ci sono celle evidenziate perche' avevo appena tirato il dado
				
				log.println("BoardPanel: rimuovo evidenziazione celle rimaste evidenziate dopo il lancio del dado");
				
				ColorPawn key = myPlayer.getPawnColor();
				
				Cell myCell=pawnPos.get(key);
			
				int myX =myCell.getXCoord();
				int myY =myCell.getYCoord();
			
				if(!myCell.isInRoom()){ /*se la pedina non era in una stanza rimuovo l'evidenziazione da tutte le celle a distanza 
				di numero ottenuto con il tiro del dado dalla cella*/
			
					log.println("BoardPanel: la mia pedina NON era in una stanza quindi rimuovo evidenziazione a tutte le celle " +
							"esterne alle stanze a distanza del tiro di dado");

					for (int x=myX-numDice; x<=myX+numDice; x++)
						for(int y=myY-numDice;y<=myY+numDice; y++)
							if(x>=0 && x<ROW && y>=0 && y<COLUMN){
								if(boardCells[x][y].isHighlighted())
									boardCells[x][y].removeHighlight();
							}
			
				}
			
				else{ /* se ero in una stanza devo rimuovere l'evidenziazione da tutte le celle a distanza 
				  		di numero ottenuto con il tiro del dado partendo dalle entrate della stanza */
				
				
					log.println("BoardPanel: la mia pedina era in una stanza quindi rimuovo evidenziazione a tutte le celle " +
							"esterne alla stanza a distanza del tiro di dado partendo dalle entrate della stanza");
					
					String roomName = myCell.getRoomName();
				
					LinkedList<Cell> entList = roomEnt.get(roomName);
					
					int xRoomEntrance;
					int yRoomEntrance;
				
					for(Cell entrance: entList){
					
						xRoomEntrance =entrance.getXCoord();
						yRoomEntrance =entrance.getYCoord();
				
						for (int x=xRoomEntrance-numDice; x<=xRoomEntrance+numDice; x++)
							for(int y=yRoomEntrance-numDice;y<=yRoomEntrance+numDice; y++)
								if(x>=0 && x<ROW && y>=0 && y<COLUMN){
									if(boardCells[x][y].isHighlighted())
										boardCells[x][y].removeHighlight();
								}
					
					}
				
				
				}
				
				log.println("BoardPanel: Inoltre rimuovo evidenziazione dalle celle delle stanze");
				
				
				//in ogni caso, per sicurezza cerco di rimuovere l'evidenzizione da ogni cella che fa parte di una stanza			
				
				for (Map.Entry<String,HashMap<Cell,Boolean>> entryR : roomPawns.entrySet()){
					
					HashMap<Cell,Boolean> rmCells = entryR.getValue();
					
					for (Map.Entry<Cell,Boolean> entry : rmCells.entrySet()){
					
						Cell cell=entry.getKey();
					
						if(cell.isHighlighted())
							cell.removeHighlight();
					
					}
					
				}
				
				
			}
			
			
			
		}

		 /**
	     * Rimuove la pedina del tabellone
	     * @param player il player di cui si deve rimuovere la pedina
	     */
		public void removePawn(Zombie player){
			
			String playerName = player.getNickname();

			log.println("BoardPanel: rimuovo la pedina di "+playerName+" dal tabellone");
			
			ColorPawn key = player.getPawnColor();

			
			Cell oldCell=pawnPos.get(key);
			
			if(oldCell==null) return; // avevo gia' rimosso questa pedina
			
			
			oldCell.removePawn();
			
			//se ero in una stanza devo liberare la cella che avevo occupato
			if(oldCell.isInRoom()){
				
				String roomName = oldCell.getRoomName();
				
				roomPawns.get(roomName).put(oldCell, true);
				
				log.println("BoardPanel: la pedina di " + playerName + " ha liberato la cella della stanza " + roomName+ " che teneva occupata");
				
			}
			
			pawnPos.put(key,null); //la pedina non fa piu' parte del tabellone
			log.println("BoardPanel: ho rimosso la pedina dalla mappa pawnPos<ColorePedina,Cella>");

						
			System.out.println("BoardPanel: E' stata rimossa la pedina di "+ playerName);
			
		}

		
		@Override
		public void componentMoved(ComponentEvent e) {
			
		}



		@Override
		public void componentShown(ComponentEvent e) {
			
		}



		@Override
		public void componentHidden(ComponentEvent e) {
			
		}


		@Override
		public void mouseClicked(MouseEvent e) {
		
		
			if (e.getClickCount()!=1) return;
			
			log.println("BoardPanel: ho fatto click sulla cella in cui mi voglio spostare");
			
			//ho cliccato sulla casella in cui voglio muovere la pedina
			
			Cell clickedCell = (Cell) e.getComponent();
			
			log.println("BoardPanel: la cella che ho cliccato ha coordinate ("+clickedCell.getXCoord()+","+clickedCell.getYCoord()+") sul tabellone");
							
			ColorPawn key = myPlayer.getPawn().getColor();
			
			//cerco in che casella era prima la mia pedina
			Cell oldCell=pawnPos.get(key);
			
			int oldX =oldCell.getXCoord();
			int oldY =oldCell.getYCoord();
			
			if(!oldCell.isInRoom()){ /*se la pedina non era in una stanza rimuovo l'evidenziazione da tutte le celle a distanza 
			di numero ottenuto con il tiro del dado dalla cella*/
			
				log.println("BoardPanel: la mia pedina NON era in una stanza quindi rimuovo evidenziazione a tutte le celle " +
						"esterne alle stanze a distanza del tiro di dado");

				
				for (int x=oldX-numDice; x<=oldX+numDice; x++)
					for(int y=oldY-numDice;y<=oldY+numDice; y++)
						if(x>=0 && x<ROW && y>=0 && y<COLUMN){
							if(boardCells[x][y].isHighlighted())
								boardCells[x][y].removeHighlight();
						}
			
			}
			
			else{ /* se ero in una stanza devo rimuovere l'evidenziazione da tutte le celle a distanza 
				  di numero ottenuto con il tiro del dado partendo dalle entrate della stanza */
				
				log.println("BoardPanel: la mia pedina era in una stanza quindi rimuovo evidenziazione a tutte le celle " +
						"esterne alla stanza a distanza del tiro di dado partendo dalle entrate della stanza");
				
				String roomName = oldCell.getRoomName();
				
				LinkedList<Cell> entList = roomEnt.get(roomName);
					
				int xRoomEntrance;
				int yRoomEntrance;
				
				for(Cell entrance: entList){
					
					xRoomEntrance =entrance.getXCoord();
					yRoomEntrance =entrance.getYCoord();
				
					for (int x=xRoomEntrance-numDice; x<=xRoomEntrance+numDice; x++)
						for(int y=yRoomEntrance-numDice;y<=yRoomEntrance+numDice; y++)
							if(x>=0 && x<ROW && y>=0 && y<COLUMN){
								if(boardCells[x][y].isHighlighted())
									boardCells[x][y].removeHighlight();
							}
					
				}
				
				// se adesso non sono piu' nella stanza la libero
				
				log.println("BoardPanel: la mia pedina era in una stanza quindi libero la cella che tenevo occupata (se eventualmente ho fatto click ancora sulla" +
						" stessa cella della stanza piu' tardi segnero' nuovamente la cella come occupata)");
				
				HashMap<Cell,Boolean> roomCells = roomPawns.get(roomName);
				
				roomCells.put(oldCell,true);
				
				
			}
			
			
			log.println("BoardPanel: Inoltre rimuovo evidenziazione dalle celle delle stanze");

			
			//in ogni caso, per sicurezza cerco di rimuovere l'evidenzizione da ogni cella che fa parte di una stanza			
			
			for (Map.Entry<String,HashMap<Cell,Boolean>> entryR : roomPawns.entrySet()){
				
				HashMap<Cell,Boolean> rmCells = entryR.getValue();
				
				for (Map.Entry<Cell,Boolean> entry : rmCells.entrySet()){
				
					Cell cell=entry.getKey();
				
					if(cell.isHighlighted())
						cell.removeHighlight();
				
				}
				
			}
			
			secretShown=false;
						
			String myName=myPlayer.getNickname();
			
			log.println("BoardPanel: rimuovo la mia pedina dalla vecchia posizione");
			//rimuovo la mia pedina dalla vecchia posizione
			oldCell.removePawn();
			
			log.println("BoardPanel: sposto la mia pedina nella nuova posizione");
			//sposto la pedina sul mio tabellone
			clickedCell.insertPawn(myPlayer.getPawn());
			System.out.println("BoardPanel: Ho spostato la mia pedina sul tabellone");
			
			log.println("BoardPanel: salvo la nuova posizione della mia pedina. \n" +
					"Poi invio un multicastSendInfo per aggiornare l'area info di tutti con questo spostamento.\n" +
					"Poi invio un multicatMovePawn pr far si che tutti gli altri player spostino la mia pedina nel loro tabellone");
			//salvo nuova posizione della mia pedina
			pawnPos.put(key,clickedCell);
		
			myPlayer.multicastSendInfo(myName,myPlayer.incrementMySequenceNumber(),null,"", "MovePawn");
			
			//dico a tutti che ho mosso la mia pedina
			myPlayer.multicastMovePawn(myName,myPlayer.incrementMySequenceNumber(),clickedCell.getXCoord(),clickedCell.getYCoord());
						
			if(clickedCell.isInRoom()){ //se sono finito in una stanza posso formulare un'ipotesi oppure dare la soluzione
								
				//segno la casella della stanza come occupata
				
				String roomName = clickedCell.getRoomName();
				
				log.println("BoardPanel: ho cliccato su una cella della stanza "+roomName+".\n" +
						"Invio un multicastSendInfo per comunicarlo agli altri player");
				
				myPlayer.multicastSendInfo(myName,myPlayer.incrementMySequenceNumber(),null,roomName,"Room");

				System.out.println("BoardPanel: Sono entrato nella stanza "+roomName);
				
				HashMap<Cell,Boolean> roomCells = roomPawns.get(roomName);
				
				for (Map.Entry<Cell,Boolean> entry : roomCells.entrySet()){
					
					Cell cell=entry.getKey();
					
					if(entry.getValue() && cell.equals(clickedCell)){ // se la stanza era libera
						entry.setValue(false); //adesso vi e' la mia pedina quindi e' occupata
						log.println("BoardPanel: La cella su cui ho cliccato era libera e adesso l'ho segnata come occupata");
						System.out.println("BoardPanel: Ho occupato una cella della stanza " + roomName);
					}
					
				}
				
				myPlayer.getPawn().setIsInRoom(true);
				myPlayer.getPawn().setRoomName(roomName);
				wind.enterInRoom(e.getXOnScreen(),e.getYOnScreen());
				if(oldCell.isInRoom() && oldCell.getRoomName().equals(roomName)){ //ho ricliccato sulla cella della stanza in cui ero gia'
					log.println("Ho ricliccato sulla stessa cella in cui ero prima all'interno della stanza "+roomName);
					wind.setIsDiceThrow(false);
					return;
				}
					
			}
			else{ //comunico a tutti che ho terminato il mio turno
				
				log.println("BoardPanel: ho cliccato su una cella esterna alle stanze. Adesso invio un multicastSendInfo agli altri player" +
						"per comunicare che ho terminato il turno.\nPoi invio un multicastEndTurn per terminare il mio turno");
  				myPlayer.multicastSendInfo(myName,myPlayer.incrementMySequenceNumber(),null,"","EndTurn");
				myPlayer.multicastEndTurn(myName,myPlayer.incrementMySequenceNumber(),false);
				myPlayer.getPawn().setIsInRoom(false);
			}
			
			numDice=-1;
			wind.setIsDiceThrow(true);
			
		}


		@Override
		public void mousePressed(MouseEvent e) {
			
		}


		@Override
		public void mouseReleased(MouseEvent e) {
			
		}


		@Override
		public void mouseEntered(MouseEvent e) {
			
		}


		@Override
		public void mouseExited(MouseEvent e) {
			
		}
	    
	
	
}

